package cuShapes;

import java.awt.Color;
import xml.*;

import javax.swing.event.EventListenerList;
import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.*;

import mainWindowSupport.ShapePropTable;

import actionHandlers.CurrentShapeListener;
import actionHandlers.PropertyChangeListener;

import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.List;
import actionHandlers.PQShapeListener;

@XmlTransient
public abstract class PQShape {
	
	// produce a wrapper XML element around this collection
	@XmlJavaTypeAdapter(value=LinesAdapter.class)
	// maps each member of this list to an XML element named appointment
	@XmlElement(name = "lineslist")
	protected ArrayList<PQLine> lines;
	@XmlJavaTypeAdapter(ColorAdapter.class)
	@XmlAttribute
	protected Color color;
	@XmlAttribute(required=true)
	protected String name;
	
	@XmlJavaTypeAdapter(RectangleAdapter.class)
	@XmlElement
	protected Rectangle center, resize, rect;
	@XmlTransient
	protected Rectangle workingRect;
	@XmlElement
	protected int width, height;
	
	@XmlTransient
	protected EventListenerList listenerList;
	@XmlTransient
	protected ShapePropTable propTable;

	/**********************************
	 * Constructor. 
	 */
	protected PQShape () {
		lines = new ArrayList<PQLine>();
		color = Color.black;
		listenerList = new EventListenerList();
		this.addCurrentShapeListener();
	}
	
	/***********************************
	 * 
	 * @return the list of lines that 
	 *    makes the shape
	 */
	public List<PQLine> getLineList() {
		if (lines == null) {
            lines = new ArrayList<PQLine>();
        }
        return this.lines;
	}
	
	@Override
	public String toString() {		
		return this.name;
	}
	
	public ShapePropTable getShapeTable() {
		return propTable;
	}
	
	public void setSelected(boolean bool) {
			if(bool) {
				this.propTable.removeTableModelListener();
				this.addPropertyChangeListener();
				this.firePQShapeEvent(PQShapeEvent.PQSHAPE_FOCUSED);
			} else {
				this.removePropertyChangeListener();
				this.propTable.addTableModelListener();
				//this.firePQShapeEvent(PQShapeEvent.PQSHAPE_UNFOCUSED);
			}
	}
	
    protected void firePQShapeEvent(int id) {  
          Object[] listeners = listenerList.getListenerList();
          PQShapeEvent e = null;
          for (int i = listeners.length -2; i >=0; i -= 2) {
        	  if (listeners[i] == CurrentShapeListener.class) {
        		  if (e == null) { 
        			  e = new PQShapeEvent(this, id);
        		  }
        		  
        		  switch(e.getID()) {
        		  case PQShapeEvent.PQSHAPE_FOCUSED:
        			  ((PQShapeListener)listeners[i+1]).PQShapeSelected(e);
        			  break;
        		  case PQShapeEvent.PQSHAPE_UNFOCUSED:
        			  ((PQShapeListener)listeners[i+1]).PQShapeDeselected(e);
        			  break;
        		  default:
        			  break;
        		  }
        	  } else if(listeners[i] == PropertyChangeListener.class) {
        		  if (e == null) { 
        			  e = new PQShapeEvent(this, id);
        		  }
        		  
        		  switch(e.getID()) {
        		  case PQShapeEvent.PQSHAPE_PROPERTY_CHANGED:
        			  ((PQShapeListener)listeners[i+1]).PQShapePropertyChanged(e);
        			  break;
        		  default:
        			  break;
        		  }
        	  }
          }
    }
	// by default PQShape is initialized with a CurrentShapeListener
	public void addCurrentShapeListener() {
		listenerList.add(CurrentShapeListener.class, new CurrentShapeListener());
		//enableEvents(0);
	}
	
	public void addPropertyChangeListener() {
		listenerList.add(PropertyChangeListener.class, new PropertyChangeListener());
	}
	public void removePropertyChangeListener() {
		listenerList.remove(PropertyChangeListener.class, listenerList.getListeners(PropertyChangeListener.class)[0]);
	}
	
	
	/***********************************
	 *  Draws each of the lines in the 
	 *    line list, applies the name
	 *    and fills the center and resize
	 *    rects.  
	 * @param g2
	 */
	public void drawToCanvas(Graphics2D g2) {
		for (PQLine line : lines) {
			line.drawLine(g2);
		}

		g2.drawString(name, center.x-14, resize.y-10);
		//g2.setColor(new Color(255,255,255));
		//g2.fill(rect);
		g2.setColor(new Color(0,0,0,75));
		g2.fill(center);
		g2.fill(resize);
	}
	

	
	/* Getters */
	public Color 		getColor(){ 		return this.color; }
	public String 		getName(){ 			return this.name; }
	public Rectangle 	getRect(){			return this.rect;	}
	public Rectangle 	getCenterRect(){	return this.center;	}
	public Rectangle	getResizeRect(){	return this.resize; }
	public Rectangle	getWorkingRect(){	return this.workingRect; }
    public Point 		getStart() {		return lines.get(0).getStart();	}   
    public Point 		getEnd() {			return lines.get(0).getEnd();	}
	
	/* Setters */
	public void setWorkingRect(Rectangle r) { workingRect = r; }
		
	/*  Abstract Methods */
    public void setStart(Point start) {
    	this.firePQShapeEvent(PQShapeEvent.PQSHAPE_PROPERTY_CHANGED);
    }
    public void setEnd(Point end) {
    	this.firePQShapeEvent(PQShapeEvent.PQSHAPE_PROPERTY_CHANGED);;
    }
    public void setName(String name) {
    	this.name = name;
    }
    public void setColor(Color color) {
    	this.color = color;
    	for(PQLine x : lines) {
    		x.setColor(color);
    	}
    }
    
	public abstract void moveWorkingRect(Point p);
	public abstract boolean hitRect(Point p);
    
    public abstract int getWidth();
    public abstract int getHeight();

    public abstract String getShapeClass();
    
    	
}
